package com.sunlands.zlcx.usercenter.service;

import com.google.common.collect.Lists;
import com.sunlands.zlcx.usercenter.constant.LearningStatus;
import com.sunlands.zlcx.usercenter.constant.YN;
import com.sunlands.zlcx.usercenter.domain.ParentTargetDO;
import com.sunlands.zlcx.usercenter.domain.TargetDO;
import com.sunlands.zlcx.usercenter.domain.UsersStudyInfoDO;
import com.sunlands.zlcx.usercenter.domain.UsersTargetRelationDO;
import com.sunlands.zlcx.usercenter.exception.CheckParamException;
import com.sunlands.zlcx.usercenter.exception.CheckRunException;
import com.sunlands.zlcx.usercenter.exception.CheckTargetException;
import com.sunlands.zlcx.usercenter.repository.ParentTargetRepository;
import com.sunlands.zlcx.usercenter.repository.TargetRepository;
import com.sunlands.zlcx.usercenter.repository.UsersTargetRepository;
import com.sunlands.zlcx.usercenter.service.status.common.StatusContext;
import com.sunlands.zlcx.usercenter.service.status.common.StatusContextFactory;
import com.sunlands.zlcx.usercenter.util.AssertUtil;
import com.sunlands.zlcx.usercenter.util.BeanPropertiesUtil;
import com.sunlands.zlcx.usercenter.util.CalendarUtil;
import com.sunlands.zlcx.usercenter.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import static com.sunlands.zlcx.usercenter.config.RedisConfig.CacheKeys.*;

/**
 * @author gaoyanfeng
 * description: 学习目标
 */
@Service
@Slf4j
public class TargetServiceImpl implements BeanPropertiesUtil {
    @Cacheable(value = TARGET_LIST, key = "#targetType")
    public List<ParentTargetVO> examList(Integer targetType) {
        List<ParentTargetDO> parentTargetDOList = parentTargetRepository.findByTargetTypeOrderByOrdersAsc(targetType);
        List<Long> ids = parentTargetDOList.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<TargetDO> targetDOList = targetRepository.findAllByParentIdIn(ids);
        List<ParentTargetVO> parentTargetVOList = Lists.newArrayList();
        for (ParentTargetDO parentTargetDO : parentTargetDOList) {
            ParentTargetVO parentTargetVO = ParentTargetVO.from(parentTargetDO);
            parentTargetVOList.add(parentTargetVO);
            List<TargetVO> targetVOList = Lists.newArrayList();
            parentTargetVO.setTargetVOList(targetVOList);
            Iterator<TargetDO> iterator = targetDOList.iterator();
            while (iterator.hasNext()) {
                TargetDO next = iterator.next();
                if (next.getParentId() == parentTargetDO.getId().intValue()) {
                    targetVOList.add(TargetVO.from(next));
                    iterator.remove();
                }
            }
        }
        return parentTargetVOList;
    }

    @CacheEvict(cacheNames = TARGET_LIST, key = "0")
    public ParentTargetDO addParentTarget(ParentTargetVO parentTargetVO) {
        ParentTargetDO parentTargetDO = null;
        if (null != parentTargetVO.getTargetName()) {
            if (parentTargetRepository.countByTargetName(parentTargetVO.getTargetName()) > 0) {
                throw new CheckParamException("父目标名称已经存在");
            }
        }
        if (null == parentTargetVO.getId()) {
            parentTargetDO = new ParentTargetDO();
            parentTargetDO.setTargetType(ParentTargetDO.TargetEnums.EXAM.getTargetType());
        } else {
            parentTargetDO = parentTargetRepository.findOne(parentTargetVO.getId());
            if (null == parentTargetDO) {
                throw new CheckParamException("父目标id不存在");
            }
            targetRepository.updateTarget(parentTargetDO.getId(), parentTargetDO.getStatus(), parentTargetVO.getTargetName());
        }
        parentTargetDO.setStatus(YN.YES.getCode());
        parentTargetDO.setTargetName(parentTargetVO.getTargetName());
        parentTargetDO.setOrders(parentTargetVO.getOrders());
        return parentTargetRepository.save(parentTargetDO);
    }

    @CacheEvict(cacheNames = TARGET_LIST, key = "0")
    @Transactional(rollbackFor = Exception.class)
    public TargetDO addTarget(TargetVO targetVO) {
        TargetDO targetDO = null;
        if (null != targetVO.getTargetName()) {
            if (targetRepository.countByTargetName(targetVO.getTargetName()) > 0) {
                throw new CheckParamException("目标名称已经存在");
            }
        }
        if (null == targetVO.getId()) {
            targetDO = new TargetDO();
            targetDO.setParentId(targetVO.getParentId());
            ParentTargetDO parentTargetDO = parentTargetRepository.findOne(targetVO.getParentId());
            targetDO.setParentName(parentTargetDO.getTargetName());
        } else {
            targetDO = targetRepository.findOne(targetVO.getId());
            if (null == targetDO) {
                throw new CheckParamException("目标id不存在");
            }
        }
        targetDO.setStatus(YN.YES.getCode());
        targetDO.setTargetName(targetVO.getTargetName());
        targetDO.setOrders(targetVO.getOrders());
        return targetRepository.save(targetDO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(cacheNames = USER_TARGET_BY_USERID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USER_STUDY_HOURS_BY_USERID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USERS_BY_ID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USERS_BY_PHONE, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null")
    })
    public void addUserTarget(UsersTargetRelationVO usersTargetRelationVO) throws ExecutionException {
        UsersVO usersVO = usersService.find(usersTargetRelationVO.getUserId());
        if (null == usersVO) {
            throw new CheckRunException("用户不存在" + usersTargetRelationVO.getUserId());
        }
        if (AssertUtil.isNotEmpty(usersVO.getCurrentLearnTargetId())) {
            throw new CheckParamException("请删除或归档当前目标后新增");
        }
        TargetDO targetDO;
        if (null != usersTargetRelationVO.getTargetId()) {
            targetDO = targetRepository.findOne(usersTargetRelationVO.getTargetId());
            if (null == targetDO) {
                throw new CheckParamException("目标id不存在");
            }
        } else {
            if (AssertUtil.isEmpty(usersTargetRelationVO.getTargetName())) {
                throw new CheckParamException("自定义目标名称不能为空");
            }
            //自定义目标
            targetDO = TargetDO.builder().parentId(12L)
                    .parentName("自定义")
                    .status(YN.YES.getCode())
                    .targetName(usersTargetRelationVO.getTargetName()).build();
            targetDO = targetRepository.save(targetDO);
        }
        UsersTargetRelationDO byUserIdAndStatus = usersTargetRepository.findByUserIdAndStatus(usersTargetRelationVO.getUserId(), YN.YES.getCode());
        if (null != byUserIdAndStatus) {
            throw new CheckRunException("用户当前学习目标未结束");
        }
        UsersTargetRelationDO usersTargetRelationDO = UsersTargetRelationDO.builder()
                .userId(usersVO.getId())
                .userName("-")
                .targetId(targetDO.getId())
                .targetName(targetDO.getTargetName())
                .status(YN.YES.getCode())
                .startTime(new Date())
                .build();
        usersTargetRelationDO = usersTargetRepository.save(usersTargetRelationDO);
        // 记录用户选择目标学习生活
        UsersStudyInfoVO usersStudyInfoVO = UsersStudyInfoVO.builder()
                .type(UsersStudyInfoDO.TypeEnums.SELECT_TARGET.getCode())
                .studyInfoName(targetDO.getTargetName())
                .startTime(new Date())
                .targetId(targetDO.getId())
                .userId(usersVO.getId()).build();

        StatusContext statusContext = statusContextFactory.fetchStatusContext(UsersStudyInfoDO.TypeEnums.create(usersStudyInfoVO.getType()));
        statusContext.doLearnChange(usersStudyInfoVO, usersTargetRelationDO);
    }

    @Caching(evict = {
            @CacheEvict(cacheNames = USER_TARGET_BY_USERID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USER_STUDY_HOURS_BY_USERID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USERS_BY_ID, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null"),
            @CacheEvict(cacheNames = USERS_BY_PHONE, key = "#usersTargetRelationVO.userId", condition = "#usersTargetRelationVO.userId != null")
    })
    @Transactional(rollbackFor = Exception.class)
    public void overUserTarget(UsersTargetRelationVO usersTargetRelationVO, boolean ifdelete) throws ExecutionException {
        UsersTargetRelationDO usersTargetRelationDO = null;

        usersTargetRelationDO = usersTargetRepository.findByUserIdAndStatus(usersTargetRelationVO.getUserId(), YN.YES.getCode());
        if (null == usersTargetRelationDO) {
            throw new CheckParamException("用户目标关系不存在");
        }

        // 记录用户归档目标学习生活
        UsersStudyInfoVO usersStudyInfoVO = new UsersStudyInfoVO();
        if (ifdelete) {
            usersStudyInfoVO.setType(UsersStudyInfoDO.TypeEnums.DELETE_TARGET.getCode());
        } else {
            usersStudyInfoVO.setType(UsersStudyInfoDO.TypeEnums.ARCHIVE_TARGET.getCode());
        }
        usersStudyInfoVO.setStartTime(usersTargetRelationDO.getCreateTime());
        usersStudyInfoVO.setUserId(usersTargetRelationDO.getUserId());
        int diffDay = CalendarUtil.diffDaysByDate(usersTargetRelationDO.getCreateTime(), new Date());
        BigDecimal studyHours = usersTargetRelationDO.getStudyHours();
        usersStudyInfoVO.setStudyInfoName("我在过去的" + diffDay + "天里共学习了" + studyHours + "小时");
        usersStudyInfoVO.setStartTime(new Date());

        UsersVO usersVO = usersService.find(usersTargetRelationDO.getUserId());
        if (LearningStatus.NO_TIMING.getCode() != usersVO.getStatus()) {
            throw new CheckTargetException("正在学习中不能删除目标，请结束学习后再试");
        }
        StatusContext statusContext = statusContextFactory.fetchStatusContext(UsersStudyInfoDO.TypeEnums.create(usersStudyInfoVO.getType()));
        statusContext.doLearnChange(usersStudyInfoVO, usersTargetRelationDO);
    }


    @Cacheable(cacheNames = USER_TARGET_BY_USERID, key = "#userId")
    public UsersTargetRelationVO getUserTarget(Long userId) {
        UsersTargetRelationDO usersTargetRelationDO = usersTargetRepository.findByUserIdAndStatus(userId, YN.YES.getCode());
        if (null == usersTargetRelationDO) {
            return null;
        }
        return UsersTargetRelationVO.from(usersTargetRelationDO);
    }

    @Cacheable(cacheNames = USER_STUDY_HOURS_BY_USERID, key = "#userId")
    public BigDecimal getStudyHours(Long userId) {
        return usersTargetRepository.sumStudyHours(userId);
    }

    @Autowired
    private UsersServiceImpl usersService;
    @Autowired
    private StatusContextFactory statusContextFactory;
    @Autowired
    private TargetRepository targetRepository;
    @Autowired
    private ParentTargetRepository parentTargetRepository;
    @Autowired
    private UsersTargetRepository usersTargetRepository;


}
